home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / x / volume4 / info4.1 < prev    next >
Encoding:
Internet Message Format  |  1993-04-28  |  43.3 KB

  1. From: argv@island.uu.net (Dan Heller)
  2. Newsgroups: comp.sources.x
  3. Subject: v04INF1:  Info about installing x11-intro-doc submission
  4. Message-ID: <791@island.uu.net>
  5. Date: 5 Jun 89 18:38:55 GMT
  6. Approved: island!argv@sun.com
  7.  
  8. Submitted-by: Dan Heller <island!argv@sun.com>
  9. Archive-name: info4.1
  10. Posting-number: Volume 4, Info 1
  11.  
  12.   I am about to post a submission which contains documentation and some
  13.   introduction to X11 complete with graphics, postscript, and everything.
  14.   You must have "pic" to print this documentation.
  15.  
  16.   It is a very large submission with some very large postscript files.  So
  17.   due to the nature of the files in this posting, it was necessary to post
  18.   the submission in 6 tarmail parts -- if you don't have "btoa", then you
  19.   need to follow the following instructions to extract the sources from
  20.   these postings.  (Even if you have tarmail, you should be sure you have
  21.   the latest version of "btoa".)
  22.  
  23.   The way the files have been produced for the posting was to go to the
  24.   top of the x11-intro-doc tree and type:
  25.  
  26.     % tar fv - x11-intro-doc | compress | btoa | split
  27.  
  28.   This means that the source tree has been run thru "tar", not shar.
  29.   It has then been compressed to save on space.  But because compressed
  30.   files are in binary format, the program "btoa" (binary to ascii) was
  31.   used to put the data in ascii format for purposes of data transfer.
  32.   Finally, the result of all that has been run thru split so that each
  33.   part would be of adequate size for posting.  To unpack this archive,
  34.   you need to reverse the process by concatenating all the "parts" in
  35.   order into one file, converting the file back into binary format,
  36.   uncompressing it and finally running "tar" on it again.  This is an
  37.   easy process -- just save each posting in a file called "partN" where
  38.   "N" is the part number, remove the headers from each posting and type:
  39.     % cat part[123456] | btoa -a | uncompress | tar fxv -
  40.   Those of you who are more clever can think of easier ways to automate
  41.   this in rn, but this is the general case.
  42.   
  43.   The only potential problem you'll have now is using the correct version
  44.   of "btoa" --everything else you already have on your system.  If you
  45.   don't, you can get them from uunet (don't ask me).  This is the -new-
  46.   btoa that r$ recently posted on comp.sources.unix.  If you have the old
  47.   version, it won't work.
  48.  
  49.   So that I won't get lots of requests for the source to "btoa", I am
  50.   reposting the source for btoa here.
  51.  
  52. But first, an editorial comment:
  53.   To avoid having to explain this to hundreds of queries about why
  54.   I didn't use uuencode instead (because everyone has it), I am going to
  55.   explain it here.  First and foremost, uuencode doesn't travel well over
  56.   certain mail transport agents because it uses a "space" as a possible
  57.   conversion character.  There are some MTAs that remove trailing spaces
  58.   from the ends of lines and it would result in a file that you could
  59.   not "decode".  Secondly, the amount of ascii characters actually
  60.   generated by "btoa" is far fewer than uuencode, saving on net traffic.
  61.   Btoa also has built into it error detection and correction, to some
  62.   degree (see the full posting for more info).  And finally, it's just
  63.   so much easier to deal with -- you don't have to worry about setuid,
  64.   creating files automatically, chmod 666, and you can use btoa in a pipe.
  65.  
  66.   Altho I don't make it a rule, postings which require uuencoded files
  67.   be included are accepted, but I much prefer btoa format.  In fact,
  68.   source code submissions (especially large ones) are more easily
  69.   transferred in mail and more easily stored for me if you use tarmail
  70.   rather than shar.  But this in in my own opinion and I am not making
  71.   any requirements that people use tarmail/btoa at all.
  72.  
  73. #!/bin/sh
  74. # Stefan Parmark, Lund Institute of Technology, Sweden
  75. # shar:    Shell Archiver
  76. #    Run the following text with /bin/sh to create:
  77. #    README
  78. #    btoa.1
  79. #    btoa.doc
  80. #    Makefile.amiga_lattice
  81. #    Makefile.sun
  82. #    atob.c
  83. #    btoa.c
  84. #    btoa.h
  85. #    chksum.h
  86. #    repair.c
  87. # This archive created: Tue Feb 21 17:45:16 1989
  88. cat << \SHAR_EOF > README
  89.              BTOA version 5.2
  90.             ------------------
  91. Written by Paul Rutter, Joe Orost & Stefan Parmark.
  92.  
  93.  
  94. Btoa was created from atob/btoa which were submitted to Usenet
  95. by Paul E. Rutter. Atob and btoa has now been merged into one
  96. program, now refered to as btoa.
  97.  
  98. Btoa converts 4 binary characters to 5 ascii ones, causing a 25%
  99. expansion. Spaces will not be used, which should make it safe
  100. to send files over Usenet without risking that blanks become
  101. tabs. 
  102.  
  103. Decoding, which previously was done with atob, is now an option
  104. of btoa. See the manual for details.
  105.  
  106. One of the drawbacks with the previous version of btoa was that,
  107. if there was an error in the file, atob only stated so, but gave
  108. no clue to its location. It used a checksum covering the
  109. total file, making it impossible to detect where the error was.
  110. I added a single-byte checksum for each row.
  111.  
  112. Further, the file contained no information about the name of the
  113. output file. Rather, stdout was used. Version 5.0 has the feature
  114. to name the file contents. It can be turned off by reading data
  115. from stdin.
  116.  
  117. A totally new feature is the ability to mend corrupted archives.
  118. This can be done as long as the header and last line are OK.
  119. It detects bad lines, informs the remote computer about this,
  120. which retransmits these lines in a special file, which btoa uses
  121. to repair the archive. See the manual for more details.
  122.  
  123. Btoa uses characters between '!' and 'u'. Special characters are
  124. 'z' meaning 4 consecutive zeros, 'y' meaning 4 spaces, and
  125. 'x' as an end-of-archive mark. The 'y' was added be me, and will
  126. not be recognized by the old version.
  127.  
  128. Old btoa encoding is still possible, as an extra option (see the
  129. manual). When decoding, btoa can tell if it's the old or new btoa
  130. format by looking at the header.
  131.  
  132. I removed the feature to exit with no output if there was en error
  133. in the archive. This was done by using a temporary file for
  134. storage. This is not a good idea for micro computer folks like
  135. me, with limited storage possibilities. I hope all realize that
  136. you shouldn't run a file that was created from a corrupted archive.
  137.  
  138. Most of the code was rewritten in order to make it execute faster.
  139. Special efforts have been made to optimize the atob part.
  140. Measured speeds are 30 kbyte/s on a Sun-3 and 4 kbyte/s on an
  141. Amiga. On the Amiga I used the VD0: recoverable RAM disk without
  142. FFS.
  143.  
  144. I have tested btoa on an Amiga 1000 and a Sun-3, and it has
  145. worked very well. If you find it doesn't work on your favourite
  146. computer, drop me a note to one of the addresses below, preferably
  147. the top one, and I'll see what I can do. Also, if you port and/or
  148. improve it, please send me the diffs, and I'll include them in the
  149. next release.
  150.  
  151. ---------------------- DISCLAIMER -------------------------------
  152.  
  153. I assume no responsibility for the use of btoa. It should work OK,
  154. and I have included lots of tests to make sure that files open,
  155. end-of-file is detected, etc.
  156.  
  157. Btoa is in the public domain. You may use it, give it away, and
  158. make improvements, as long as the names of the developers are
  159. mentioned and you don't use it to earn money. It may NOT be used
  160. commercially without my permission.
  161.  
  162. /Stefan Parmark
  163.         d84sp@efd.lth.se
  164.         d84spa@rigel.sunet.se
  165. SHAR_EOF
  166. cat << \SHAR_EOF > btoa.1
  167. .TH BTOA 1 "21 February 1989"
  168. .| btoa version 5.2
  169. .SH NAME
  170. btoa - encode/decode binary to printable ASCII
  171. .SH SYNOPSIS
  172. btoa [-adhor] [input filename] [output filename]
  173. .SH DESCRIPTION
  174. .I Btoa
  175. is a filter which reads binary bytes from the input file and
  176. generates printable ASCII characters on the output file. It attaches
  177. a header and a checksum to the archive. It can also reverse this,
  178. creating a binary file from the archive.
  179. .LP
  180. Since last version of
  181. .I btoa/atob,
  182. several new features have been
  183. added. The most obvious one is that
  184. .I atob
  185. has been integrated
  186. with
  187. .I btoa.
  188. They are now the same program which is called with
  189. different arguments. Another is the ability to repair damaged
  190. archives.
  191. .LP
  192. The new version is compatible with the old version, that is,
  193. it can still encode and decode old btoa files.
  194. .LP
  195. .I Btoa
  196. has an option to decode the archive, restoring the binary bytes.
  197. It strips the input file until it finds a valid header, and continues
  198. decoding until the end mark is found. It recognices both old- and
  199. new-style headers, and can decode both. It is possible to leave out
  200. the destination name when decoding new-style archives, because the
  201. name is stored in the header. Entering a name will override the
  202. autonaming function.
  203. .LP
  204. It is possible to leave out the file names and redirect stdin and
  205. stdout with '<' and '>' to the desired files. This is to maintain
  206. compatibility with earlier versions of
  207. .I btoa.
  208. .LP
  209. .I Btoa
  210. now adds a single byte checksum to each row in the archive.
  211. When an error is found, diagnosis automatically starts and produces
  212. a diagnosis file which can be used to extract the damaged part from
  213. an errorfree archive. The extracted part can then be used to correct
  214. the damaged archive.
  215. .I Btoa
  216. has options to perform the reparation
  217. automatically. This is especially useful when downloading data
  218. converted to text files, and occasionally finding that an archive
  219. file of considerable size turns is corrupted.
  220. .SH FEATURES
  221. .I Btoa
  222. encodes 4 binary bytes into 5 characters, expanding the file by
  223. 25%. As a special case 4 zeroes will be encoded as 'z' and 4
  224. spaces as 'y'. This makes it possible to compress the archive a bit.
  225. .SH OPTIONS
  226. .IP -h
  227. Shows help on 
  228. .I btoa.
  229. .LP
  230. .IP-a
  231. Switches to
  232. .I atob
  233. (decoding) mode.
  234. .LP
  235. .IP -o
  236. Switches to old version of
  237. .I btoa.
  238. .LP
  239. .IP -d
  240. Extracts repair file from diagnosis file. This assumes that
  241. an undamaged version of the archive and a file called
  242. 'btoa.dia' is present.
  243. .LP
  244. .IP-r
  245. Repairs the damaged archive. A file named 'btoa.rep' must
  246. be present for this to work.
  247. .SH EXAMPLES
  248. Below follows a description of a normal repair session. Lines
  249. beginning with 'Local>' were typed on the computer to which the
  250. file was downloaded. Accordingly, lines typed on the connected
  251. computer will begin with 'Remote>'. Sending a file to the other
  252. computer will be noted as 'transmit file'.
  253. .LP
  254. A normal repairing procedure is as follows:
  255. Local> btoa -a file.btoa
  256. btoa: Bad checksum on line 2648.
  257. btoa: Starting diagnosis.
  258. btoa: Diagnosis output to 'btoa.dia'.
  259. Local> transmit btoa.dia
  260. .LP
  261. Remote> btoa -d file.btoa
  262. btoa: Repair output to 'btoa.rep'.
  263. Remote> transmit btoa.rep
  264. .LP
  265. Local> btoa -a btoa.rep
  266. btoa: Repaired archive written to 'btoa.rdy'.
  267. .LP
  268. You can now erase file.btoa and decode btoa.rdy using 'btoa -a btoa.rdy'.
  269. .SH AUTHORS
  270. Paul Rutter  Joe Orost  Stefan Parmark
  271. .SH KNOWN BUGS
  272. .I Btoa
  273. will not work properly unless the input is a true file or a
  274. redirected one. This is because file positions are collected during
  275. diagnosis for later reference when producing the diagnosis file.
  276. The bug is actually in fseek() which only can reposition 'real' files.
  277. .LP
  278. Send bug reports to d84sp@efd.lth.se (Stefan Parmark).
  279. SHAR_EOF
  280. cat << \SHAR_EOF > btoa.doc
  281.  
  282.  
  283.  
  284. BTOA(1)                  USER COMMANDS                    BTOA(1)
  285.  
  286.  
  287.  
  288. NAME
  289.      btoa - encode/decode binary to printable ASCII
  290.  
  291. SYNOPSIS
  292.      btoa -adhor input filename output filename
  293.  
  294. DESCRIPTION
  295.      Btoa is a filter which reads binary  bytes  from  the  input
  296.      file  and generates printable ASCII characters on the output
  297.      file. It attaches a header and a checksum to the archive. It
  298.      can  also  reverse  this,  creating  a  binary file from the
  299.      archive.
  300.  
  301.      Since last version of btoa/atob, several new  features  have
  302.      been  added.  The  most  obvious  one  is that atob has been
  303.      integrated with btoa. They are now the same program which is
  304.      called  with  different arguments. Another is the ability to
  305.      repair damaged archives.
  306.  
  307.      The new version is compatible with the old version, that is,
  308.      it can still encode and decode old btoa files.
  309.  
  310.      Btoa has an option to  decode  the  archive,  restoring  the
  311.      binary  bytes.   It  strips  the input file until it finds a
  312.      valid header, and continues decoding until the end  mark  is
  313.      found.  It  recognices  both old- and new-style headers, and
  314.      can decode both. It is possible to leave out the destination
  315.      name  when  decoding new-style archives, because the name is
  316.      stored in the header. Entering  a  name  will  override  the
  317.      autonaming function.
  318.  
  319.      It is possible to leave out  the  file  names  and  redirect
  320.      stdin and stdout with '<' and '>' to the desired files. This
  321.      is to maintain compatibility with earlier versions of btoa.
  322.  
  323.      Btoa now adds a single byte checksum  to  each  row  in  the
  324.      archive.   When  an  error is found, diagnosis automatically
  325.      starts and produces a diagnosis file which can  be  used  to
  326.      extract  the  damaged  part  from  an errorfree archive. The
  327.      extracted part can then  be  used  to  correct  the  damaged
  328.      archive.    Btoa  has  options  to  perform  the  reparation
  329.      automatically. This is especially  useful  when  downloading
  330.      data  converted to text files, and occasionally finding that
  331.      an archive file of considerable size turns is corrupted.
  332.  
  333. FEATURES
  334.      Btoa encodes 4 binary bytes into 5 characters, expanding the
  335.      file  by  25%. As a special case 4 zeroes will be encoded as
  336.      'z' and 4 spaces as 'y'. This makes it possible to  compress
  337.      the archive a bit.
  338.  
  339.  
  340.  
  341.  
  342.  
  343.                   Last change: 21 February 1989                 1
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350. BTOA(1)                  USER COMMANDS                    BTOA(1)
  351.  
  352.  
  353.  
  354. OPTIONS
  355.      -h   Shows help on btoa.
  356.  
  357.      -a   Switches to atob (decoding) mode.
  358.  
  359.      -o   Switches to old version of btoa.
  360.  
  361.      -d   Extracts repair file from diagnosis file. This  assumes
  362.           that  an  undamaged  version  of the archive and a file
  363.           called
  364.  
  365.      -r   Repairs the damaged archive. A  file  named  'btoa.rep'
  366.           must be present for this to work.
  367.  
  368. EXAMPLES
  369.      Below follows a description  of  a  normal  repair  session.
  370.      Lines  beginning with 'Local>' were typed on the computer to
  371.      which the file was downloaded. Accordingly, lines  typed  on
  372.      the  connected computer will begin with 'Remote>'. Sending a
  373.      file to the other computer will be noted as 'transmit file'.
  374.  
  375.      A normal repairing procedure is as follows: Local>  btoa  -a
  376.      file.btoa  btoa:  Bad checksum on line 2648.  btoa: Starting
  377.      diagnosis.  btoa: Diagnosis output  to  'btoa.dia'.   Local>
  378.      transmit btoa.dia
  379.  
  380.      Remote> btoa -d file.btoa btoa: Repair output to 'btoa.rep'.
  381.      Remote> transmit btoa.rep
  382.  
  383.      Local> btoa -a btoa.rep btoa: Repaired  archive  written  to
  384.      'btoa.rdy'.
  385.  
  386.      You can now erase file.btoa and decode btoa.rdy using  'btoa
  387.      -a btoa.rdy'.
  388.  
  389. AUTHORS
  390.      Paul Rutter  Joe Orost  Stefan Parmark
  391.  
  392. KNOWN BUGS
  393.      Btoa will not work properly unless the input is a true  file
  394.      or a redirected one. This is because file positions are col-
  395.      lected during diagnosis for later reference  when  producing
  396.      the  diagnosis  file.   The bug is actually in fseek() which
  397.      only can reposition 'real' files.
  398.  
  399.      Send bug reports to d84sp@efd.lth.se (Stefan Parmark).
  400.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.                   Last change: 21 February 1989                 2
  410.  
  411.  
  412.  
  413. SHAR_EOF
  414. cat << \SHAR_EOF > Makefile.amiga_lattice
  415. OBJS     = btoa.o atob.o repair.o
  416. CFLAGS   = -cef -dLATTICE -v -w
  417.  
  418. btoa     : $(OBJS)
  419.            blink lib:c.o $(OBJS) TO btoa LIB lib:lcs.lib SC SD ND
  420.  
  421. atob.o   : atob.c btoa.h chksum.h
  422. btoa.o   : btoa.c btoa.h chksum.h
  423. repair.o : repair.c btoa.h
  424. SHAR_EOF
  425. cat << \SHAR_EOF > Makefile.sun
  426. OBJS     = btoa.o atob.o repair.o
  427.  
  428. btoa     : $(OBJS)
  429.            cc -O $(OBJS) -o btoa
  430.  
  431. btoa.o   : btoa.c btoa.h chksum.h
  432.            cc -c -O btoa.c
  433. atob.o   : atob.c btoa.h chksum.h
  434.            cc -c -O atob.c
  435. repair.o : repair.c btoa.h
  436.            cc -c -O repair.c
  437. SHAR_EOF
  438. cat << \SHAR_EOF > atob.c
  439. /* atob.c */
  440.  
  441. /* Written by Paul Rutter, Joe Orost & Stefan Parmark. */
  442.  
  443. #include <stdio.h>
  444. #ifdef AMIGA
  445. #include <stdlib.h>
  446. #include <string.h>
  447. #endif AMIGA
  448.  
  449. #include "btoa.h"
  450. #if USE_MACROS
  451. #include "chksum.h"
  452. #endif USE_MACROS
  453.  
  454.  
  455. BYTE atob(infile)
  456. register FILE *infile;
  457. {
  458.   register BYTE error;
  459.   register LONG filepos;
  460.   int maxperline;
  461.   LONG n1, n2, oeor, osum, orot, lastline;
  462.   static BYTE outfilename[BUFSIZE];
  463.   extern LONG Ceor, Csum, Crot;
  464.   extern FILE *outfile;
  465.   extern BYTE new_version, openoutput, buffer[BUFSIZE];
  466.  
  467.   error = FALSE;
  468.  
  469.   /* Search for archive header. */
  470.   do
  471.   {
  472.     filepos = ftell(infile);
  473.  
  474.     if (readbuffer(buffer, "archive", infile))
  475.       error = TRUE;
  476.   }
  477.   while (!(error || strncmp(buffer, "xbtoa", 5) == 0));
  478.  
  479.   if (!error)
  480.     if (strcmp(buffer, "xbtoa Begin\n") == 0)
  481.     {
  482.       new_version = FALSE;
  483.       fprintf(stderr, "btoa: Old btoa format.\n");
  484.     }
  485.     else if (sscanf(buffer, "xbtoa5 %d %s Begin\n", &maxperline, outfilename) == 2)
  486.     {
  487.       new_version = TRUE;
  488.       /* Naming a file overrides the read-name-from-file function. */
  489.       if (!openoutput && strcmp(outfilename, "-") != 0)
  490.         if ((outfile = fopen_write(outfilename)) == NULL)
  491.           error = TRUE;
  492.         else
  493.           openoutput = TRUE;
  494.     }
  495.     else
  496.     {
  497.       fprintf(stderr, "btoa: Illegal archive header.\n");
  498.       error = TRUE;
  499.     }
  500.  
  501.   if (!error)
  502.   {
  503.     Ceor = Csum = Crot = 0;
  504.  
  505.     if (new_version)
  506.       error = new_decodefile(infile, &lastline, filepos, maxperline);
  507.     else
  508.       error = old_decodefile(infile, &lastline);
  509.   }
  510.  
  511.   if (!error)
  512.   {
  513.     if (sscanf(buffer, "xbtoa End N %ld %lx E %lx S %lx R %lx\n",
  514.         &n1, &n2, &oeor, &osum, &orot) != 5)
  515.     {
  516.       fprintf(stderr, "btoa: Bad format on line %ld. Can't repair file.\n",
  517.           lastline);
  518.       error = TRUE;
  519.     }
  520.     else if ((n1 != n2) || (oeor != Ceor) || (osum != Csum) || (orot != Crot))
  521.     {
  522.       fprintf(stderr, "btoa: Bad file checksum. Can't repair file.\n");
  523.       error = TRUE;
  524.     }
  525.     else
  526.       /* Flush last characters. */
  527.       decode_line(NULL, (int) ((n1 - 1) & 0x03));
  528.   }
  529.  
  530.   return(error);
  531. }
  532.  
  533.  
  534. /* Peek at the next byte without moving the file pointer. */
  535. int nextbyte(infile)
  536. register FILE *infile;
  537. {
  538.   register int ch;
  539.   register LONG filepos;
  540.  
  541.   filepos = ftell(infile);
  542.   ch = fgetc(infile);
  543.   fseek(infile, filepos, 0);
  544.  
  545.   return(ch);
  546. }
  547.  
  548.  
  549. BYTE new_decodefile(infile, lastline, filepos, maxperline)
  550. register FILE *infile;
  551. LONG *lastline, filepos;
  552. int maxperline;
  553. {
  554.   register int length;
  555.   int ch;
  556.   register BYTE stop, error, newerror, errorstart;
  557.   register LONG line, prevfilepos, startpos;
  558.   struct Diagnosis diagnosislist;
  559.   extern LONG Csum;
  560.   extern BYTE buffer[BUFSIZE];
  561.  
  562.   error = FALSE;
  563.  
  564.   line = 1;  /* Current line number. */
  565.  
  566.   /* A sequence of errors is indicated by errorstart. When it */
  567.   /* changes from TRUE to FALSE a diagnosis record will be    */
  568.   /* generated.                                               */
  569.   stop = errorstart = FALSE;
  570.  
  571.   /* File position of the line before the error sequence.     */
  572.   /* That is the last correct line.                           */
  573.   startpos = 0;
  574.  
  575.   while (!stop)
  576.   {
  577.     prevfilepos = filepos;
  578.     filepos = ftell(infile);
  579.  
  580.     /* Newerror indicates an error on the current line. */
  581.     newerror = FALSE;
  582.  
  583.     line++;
  584.     if (readbuffer(buffer, "archive", infile))
  585.       newerror = stop = TRUE;
  586.     else if (buffer[0] == 'x')  /* End of archive found. */
  587.       stop = TRUE;
  588.     else if ((length = strlen(buffer) - 1) != maxperline ||
  589.              buffer[length] != '\n')
  590.     {
  591.       /* If last character wasn't end-of-line, then we */
  592.       /* have to read until it is found.               */
  593.       if (buffer[length] != '\n')
  594.       {
  595.         newerror = TRUE;
  596.         while ((ch = fgetc(infile)) != EOF && (BYTE)ch != '\n')
  597.           ;
  598.         if (ch == EOF)
  599.           stop = TRUE;
  600.       }
  601.       else if (length > maxperline || nextbyte(infile) != 'x')
  602.       {
  603.         newerror = TRUE;
  604.         Csum = DECODE(buffer[length - 1]);  /* Make Csum correct (modulo 85). */
  605.       }
  606.  
  607.       if (newerror)
  608.         fprintf(stderr, "btoa: Bad line length on line %ld.\n", line);
  609.     }
  610.  
  611.     if (!(newerror || stop))
  612.     {
  613.       if (decode_line(buffer, length - 1))
  614.       {
  615.         if (!error)
  616.           fprintf(stderr, "btoa: Bad character on line %ld.\n", line);
  617.         newerror = TRUE;
  618.       }
  619.  
  620.       /* Examine checksum. */
  621.       if ((ch = buffer[length - 1]) == ENCODE(Csum % 85))
  622.       {
  623.         if (errorstart)
  624.         {
  625.           intodiagnosislist(&diagnosislist, startpos, filepos);
  626.           errorstart = FALSE;
  627.         }
  628.       }
  629.       else
  630.       {
  631.         newerror = TRUE;
  632.         fprintf(stderr, "btoa: Bad checksum on line %ld.\n", line);
  633.         Csum = DECODE(ch);  /* Make Csum correct (modulo 85). */
  634.       }
  635.     }
  636.  
  637.     if (newerror)
  638.     {
  639.       if (!error)
  640.       {
  641.         fprintf(stderr, "btoa: Starting diagnosis.\n");
  642.         diagnosislist.next = diagnosislist.last = NULL;
  643.       }
  644.  
  645.       error = TRUE;
  646.       if (!errorstart)
  647.       {
  648.         errorstart = TRUE;
  649.         startpos = prevfilepos;
  650.       }
  651.     }
  652.   }
  653.  
  654.   if (error)
  655.   {
  656.     if (errorstart)
  657.       intodiagnosislist(&diagnosislist, startpos, filepos);
  658.     producediagnosis(&diagnosislist, infile);
  659.   }
  660.  
  661.   *lastline = line;
  662.  
  663.   return(error);
  664. }
  665.  
  666.  
  667.  
  668. BYTE old_decodefile(infile, lastline)
  669. register FILE *infile;
  670. LONG *lastline;
  671. {
  672.   register int length;
  673.   register BYTE stop, error;
  674.   register LONG line;
  675.   extern BYTE buffer[BUFSIZE];
  676.  
  677.   error = FALSE;
  678.  
  679.   line = 1;
  680.   stop = FALSE;
  681.   while (!stop)
  682.   {
  683.     line ++;
  684.  
  685.     if (readbuffer(buffer, "archive", infile))
  686.       error = stop = TRUE;
  687.     else if (buffer[0] == 'x')  /* End of archive found. */
  688.       stop = TRUE;
  689.     else
  690.     {
  691.       length = strlen(buffer) - 1;
  692.       if (buffer[length] != '\n')
  693.         error = stop = TRUE;  /* The line was longer than the buffer. */
  694.     }
  695.  
  696.     if (!stop)
  697.     {
  698.       if (decode_line(buffer, length))
  699.       {
  700.         fprintf(stderr, "btoa: Bad character on line %ld.\n", line);
  701.         error = stop = TRUE;
  702.       }
  703.     }
  704.   }
  705.  
  706.   *lastline = line;
  707.  
  708.   return(error);
  709. }
  710.  
  711.  
  712. BYTE decode_line(buffer, length)
  713. register BYTE *buffer;
  714. register int length;
  715. {
  716.   register int ch;
  717.   register BYTE error;
  718.   register LONG tmp_codeword;
  719.   extern BYTE new_version;
  720.   extern FILE *outfile;
  721.   static LONG codeword;
  722.   static int ch1, ch2, ch3, ch4;
  723.   static BYTE bytecount = 0;
  724.  
  725.   error = FALSE;
  726.  
  727.   if (buffer == NULL)  /* Flush last characters. */
  728.   {
  729.     if (bytecount > 0)
  730.     {
  731.       fputc(ch1, outfile);
  732.       if (length > 0)
  733.         fputc(ch2, outfile);
  734.       if (length > 1)
  735.         fputc(ch3, outfile);
  736.       if (length > 2)
  737.         fputc(ch4, outfile);
  738.     }
  739.   }
  740.   else
  741.   {
  742.     while (length > 0)
  743.     {
  744.       length--;
  745.       ch = *buffer++;
  746.  
  747.       /* Delayed output. This is to make sure that files with lengths */
  748.       /* that are not multiples of 4 won't become too long.           */
  749.       if (bytecount == 5)
  750.       {
  751.         fputc(ch1, outfile);
  752.         fputc(ch2, outfile);
  753.         fputc(ch3, outfile);
  754.         fputc(ch4, outfile);
  755.  
  756.         bytecount = 0;
  757.       }
  758.  
  759.       if (new_version)
  760.         calcchecksum(ch);
  761.  
  762.       if (((BYTE)ch >= '!') && ((BYTE)ch < ('!' + 85)))  /* Valid characters. */
  763.       {
  764.         /* See if we can take all 5 bytes and decode them right away. */
  765.         /* That is, if all remaining bytes are on the current line.   */
  766.         if (length >= 4 - bytecount)
  767.         {
  768.           length -= 4 - bytecount;
  769.  
  770.           if (bytecount == 0)
  771.             codeword = DECODE(ch);
  772.           else
  773.             codeword = codeword * 85 + DECODE(ch);
  774.  
  775.           for (bytecount++; bytecount < 5; bytecount++)
  776.           {
  777.             ch = *buffer++;
  778.             if (new_version)
  779.               calcchecksum(ch);
  780.             codeword = codeword * 85 + DECODE(ch);
  781.           }
  782.         }
  783.         else
  784.         {
  785.           /* Shift codeword and insert character. */
  786.  
  787.           if (bytecount == 0)
  788.           {
  789.             codeword = DECODE(ch);
  790.             bytecount = 1;
  791.           } 
  792.           else /* bytecount < 5 */
  793.           {
  794.             codeword = codeword * 85 + DECODE(ch);
  795.             bytecount ++;
  796.           }
  797.         }
  798.  
  799.         if (bytecount == 5)
  800.         {
  801.           tmp_codeword = codeword;
  802.  
  803.           ch4 = (int)tmp_codeword & 0xFF;
  804.           ch3 = (int)(tmp_codeword >>= 8) & 0xFF;
  805.           ch2 = (int)(tmp_codeword >>= 8) & 0xFF;
  806.           ch1 = (int)(tmp_codeword >> 8) & 0xFF;
  807.  
  808.           if (!new_version)
  809.           {
  810.             calcchecksum(ch1);
  811.             calcchecksum(ch2);
  812.             calcchecksum(ch3);
  813.             calcchecksum(ch4);
  814.           }
  815.         }
  816.       }
  817.       else if ((BYTE)ch == 'z' || (new_version && (BYTE)ch == 'y'))
  818.       {
  819.         if (bytecount != 0)
  820.           error = TRUE;
  821.         else
  822.         {
  823.           ch1 = ch2 = ch3 = ch4 = (ch == 'z') ? 0 : ' ';
  824.           if (!new_version)
  825.           {
  826.             calcchecksum(ch1);
  827.             calcchecksum(ch1);
  828.             calcchecksum(ch1);
  829.             calcchecksum(ch1);
  830.           }
  831.           bytecount = 5;
  832.         }
  833.       }
  834.       else
  835.         error = TRUE;
  836.     }
  837.   }
  838.  
  839.   return(error);
  840. }
  841. SHAR_EOF
  842. cat << \SHAR_EOF > btoa.c
  843. /* btoa.c */
  844.  
  845. /* Written by Paul Rutter, Joe Orost & Stefan Parmark. */
  846.  
  847. #include <stdio.h>
  848. #ifdef AMIGA
  849. #include <stdlib.h>
  850. #include <string.h>
  851. #endif AMIGA
  852.  
  853. #include "btoa.h"
  854. #if USE_MACROS
  855. #include "chksum.h"
  856. #endif USE_MACROS
  857.  
  858. #define VERSION  "5.2"
  859.  
  860. LONG Ceor, Csum, Crot;  /* Checksums to verify archive validity. */
  861. BYTE new_version, openoutput, buffer[BUFSIZE];
  862. FILE *outfile;
  863.  
  864.  
  865. void main(argc, argv)
  866. int argc;
  867. BYTE **argv;
  868. {
  869.   register BYTE openinput, error, ch, a_to_b, diagnosis, repair;
  870.   register BYTE *infilename, *text;
  871.   register FILE *infile;
  872.   extern BYTE new_version, openoutput;
  873.   extern FILE *outfile;
  874. #ifdef AMIGA
  875.   extern int _bufsiz;
  876.  
  877.   /* Change file buffer size. */
  878.   _bufsiz = 10240;
  879. #endif AMIGA
  880.  
  881.   error = openinput = openoutput = a_to_b = diagnosis = repair = FALSE;
  882.   new_version = TRUE;
  883.   infilename = NULL;
  884.  
  885.   /* Scan for '-' options. The rest must be file names. */
  886.   while (!error && argc > 1 && *argv[1] == '-')
  887.   {
  888.     text = &argv[1][1];
  889.     while (!error && (ch = *text++) != 0)
  890.     {
  891.       switch(ch)
  892.       {
  893.         case 'a' : /* Activate atob. */
  894.                    a_to_b = TRUE;
  895.                    break;
  896.         case 'd' : /* Extract missing part from undamaged archive. */
  897.                    diagnosis = TRUE;
  898.                    break;
  899.         case 'h' : /* Print help and abort execution. */
  900.                    error = TRUE;
  901.                    break;
  902.         case 'o' : /* Use old btoa format. */
  903.                    new_version = FALSE;
  904.                    break;
  905.         case 'r' : /* Repair damaged archive. */
  906.                    repair = TRUE;
  907.                    break;
  908.         default  : error = TRUE;
  909.       }
  910.     }
  911.     argv++;
  912.     argc--;
  913.   }
  914.  
  915.   if (argc > 3)
  916.     error = TRUE;
  917.  
  918.   if (error)
  919.     printhelp();
  920.   else
  921.   {
  922.     /* If file name was given, try to open file. Otherwise use stdin. */
  923.     if (argc > 1)
  924.     {
  925.       infilename = argv[1];
  926.       if ((infile = fopen_read(infilename)) == NULL)
  927.         error = TRUE;
  928.       else
  929.         openinput = TRUE;
  930.     }
  931.     else
  932.       infile = stdin;
  933.   }
  934.  
  935.   if (!error)
  936.   {
  937.     /* If file name was given, try to open file. Otherwise use stdout. */
  938.     if (argc > 2 && !diagnosis && !repair)
  939.     {
  940.       if ((outfile = fopen_write(argv[2])) == NULL)
  941.         error = TRUE;
  942.       else
  943.         openoutput = TRUE;
  944.     }
  945.     else
  946.       outfile = stdout;
  947.   }
  948.  
  949.   if (!error)
  950.   {
  951.     if (diagnosis)
  952.       error = producerepair(infile);
  953.     else if (repair)
  954.       error = performrepair(infile);
  955.     else if (a_to_b)
  956.       error = atob(infile);
  957.     else
  958.       error = btoa(infile, infilename);
  959.   }
  960.  
  961.   /* Close all opened files. */
  962.   if (openinput)
  963.     fclose(infile);
  964.   if (openoutput)
  965.     fclose(outfile);
  966.  
  967.   if (error)
  968.     exit(1);
  969. }
  970.  
  971.  
  972. BYTE btoa(infile, infilename)
  973. register FILE *infile;
  974. register BYTE *infilename;
  975. {
  976.   register LONG codeword, filesize;
  977.   register int ch1, ch2, ch3, ch4, readbytes;
  978.   extern FILE *outfile;
  979.   extern BYTE new_version, buffer[BUFSIZE];
  980.   extern LONG Ceor, Csum, Crot;
  981.  
  982.   Ceor = Csum = Crot = 0;
  983.  
  984.   /* Write archive header. */
  985.   if (new_version)
  986.   {
  987.     fprintf(outfile, "xbtoa5 %d %s Begin\n", MAXPERLINE,
  988.         (infilename == NULL) ? "-" : truncname(infilename));
  989.   }
  990.   else
  991.     fprintf(outfile, "xbtoa Begin\n");
  992.  
  993.   /* Encode entire input file. */
  994.   filesize = 0;
  995.   do
  996.   {
  997.     readbytes = fread(buffer, 1, 4, infile);
  998.  
  999.     if (readbytes < 4)
  1000.     {
  1001.       ch1 = (readbytes > 0) ? ((int)buffer[0] & 0xFF) : 0;
  1002.       ch2 = (readbytes > 1) ? ((int)buffer[1] & 0xFF) : 0;
  1003.       ch3 = (readbytes > 2) ? ((int)buffer[2] & 0xFF) : 0;
  1004.       ch4 = 0;
  1005.     }
  1006.     else
  1007.     {
  1008.       ch1 = (int)buffer[0] & 0xFF;
  1009.       ch2 = (int)buffer[1] & 0xFF;
  1010.       ch3 = (int)buffer[2] & 0xFF;
  1011.       ch4 = (int)buffer[3] & 0xFF;
  1012.     }
  1013.  
  1014.     if (readbytes > 0)
  1015.     {
  1016.       if (!new_version)
  1017.       {
  1018.         calcchecksum(ch1);
  1019.         calcchecksum(ch2);
  1020.         calcchecksum(ch3);
  1021.         calcchecksum(ch4);
  1022.       }
  1023.  
  1024.       codeword = (ch1 << 8) | ch2;
  1025.       codeword = (((codeword << 8) | ch3) << 8) | ch4;
  1026.       wordout(codeword);
  1027.  
  1028.       filesize += readbytes;
  1029.     }
  1030.   }
  1031.   while (readbytes == 4);
  1032.  
  1033.   asciiout(EOF);  /* Flush buffer. */
  1034.  
  1035.   /* Filesize is written twice as crude cross check. */
  1036.   fprintf(outfile, "xbtoa End N %ld %lx E %lx S %lx R %lx\n",
  1037.         filesize, filesize, Ceor, Csum, Crot);
  1038.  
  1039.   return(FALSE);  /* No errors discovered. */
  1040. }
  1041.  
  1042.  
  1043. /* Print help on how to use btoa. */
  1044. void printhelp()
  1045. {
  1046.   fprintf(stderr, "              Btoa version %s\n", VERSION);
  1047.   fprintf(stderr, "Written by Paul Rutter, Joe Orost & Stefan Parmark.\n");
  1048.  
  1049.   fprintf(stderr, "\nUsage: btoa [-{adhor}] [input file] [output file]\n");
  1050.  
  1051.   fprintf(stderr, "\nOptions:\n");
  1052.   fprintf(stderr, "-h  Shows this help list.\n");
  1053.   fprintf(stderr, "-a  Use atob rather than btoa.\n");
  1054.   fprintf(stderr, "-o  Use old version of btoa.\n");
  1055.   fprintf(stderr, "-d  Extract repair file from diagnosis file.\n");
  1056.   fprintf(stderr, "-r  Repair archive from repair file.\n");
  1057.  
  1058.   fprintf(stderr, "\nExamples:\n");
  1059.   fprintf(stderr, "  btoa -h\n");
  1060.   fprintf(stderr, "  btoa [input binary file] [output archive file]\n");
  1061.   fprintf(stderr, "  btoa -o [input binary file] [output archive file]\n");
  1062.   fprintf(stderr, "  btoa -a [input archive file] [output binary file]\n");
  1063.   fprintf(stderr, "  btoa -d [undamaged archive file]\n");
  1064.   fprintf(stderr, "  btoa -r [damaged archive file]\n");
  1065. }
  1066.  
  1067.  
  1068. #if !USE_MACROS
  1069. /* Update file checksums. */
  1070. void calcchecksum(ch)
  1071. register int ch;
  1072. {
  1073.   extern LONG Ceor, Csum, Crot;
  1074.  
  1075.   Ceor ^= ch;
  1076.   Csum += ch + 1;
  1077.  
  1078.   if (Crot & 0x80000000L)
  1079.     ch ++;
  1080.   Crot <<= 1;
  1081.   Crot += ch;
  1082. }
  1083. #endif !USE_MACROS
  1084.  
  1085.  
  1086. /* Encode 4 binary bytes to 5 ascii bytes. */
  1087. void wordout(codeword)
  1088. register LONG codeword;
  1089. {
  1090.   register int tmp, quote;
  1091.   extern BYTE new_version;
  1092.  
  1093.   if (codeword == 0)
  1094.     /* Encode 4 zeros as a 'z'. */
  1095.     asciiout('z');
  1096.   else if (new_version && codeword == 0x20202020)
  1097.     /* Encode 4 spaces as a 'y'. */
  1098.     asciiout('y');
  1099.   else
  1100.   {
  1101.     tmp = 0;
  1102.  
  1103.     /* Extra calculations because some machines don't support */
  1104.     /* unsigned longwords.                                    */
  1105.     if (codeword < 0)
  1106.     {
  1107.       tmp = 32;
  1108.       codeword -= (LONG)(85L * 85 * 85 * 85 * 32);
  1109.     }
  1110.     if (codeword < 0)
  1111.     {
  1112.       tmp = 64;
  1113.       codeword -= (LONG)(85L * 85 * 85 * 85 * 32);
  1114.     }
  1115.  
  1116.     /* Write 5 ascii bytes representing 4 binary bytes. */
  1117.  
  1118.     quote = codeword / (LONG)(85L * 85 * 85 * 85);
  1119.     codeword -= quote * (LONG)(85L * 85 * 85 * 85);
  1120.     asciiout(ENCODE(quote + tmp));
  1121.  
  1122.     quote = codeword / (LONG)(85L * 85 * 85);
  1123.     codeword -= quote * (LONG)(85L * 85 * 85);
  1124.     asciiout(ENCODE(quote));
  1125.  
  1126.     quote = codeword / (LONG)(85L * 85);
  1127.     codeword -= quote * (LONG)(85L * 85);
  1128.     asciiout(ENCODE(quote));
  1129.  
  1130.     quote = (int)codeword / 85;
  1131.     codeword -= quote * 85;
  1132.     asciiout(ENCODE(quote));
  1133.  
  1134.     asciiout(ENCODE((int)codeword));
  1135.   }
  1136. }
  1137.  
  1138.  
  1139. /* Write ch to outfile. Write '\n' for every line. */
  1140. void asciiout(ch)
  1141. register int ch;
  1142. {
  1143.   static WORD linepos = 0;
  1144.   extern FILE *outfile;
  1145.   extern LONG Csum;
  1146.   extern BYTE new_version;
  1147.  
  1148.   if (ch == EOF)  /* Signal to flush buffer. */
  1149.   {
  1150.     /* Linepos == 0 means '\n' just written in asciiout(). This */
  1151.     /* avoids bug in BITNET, which changes blank line to spaces. */
  1152.     if (linepos != 0)
  1153.     {
  1154.       if (new_version)
  1155.         fputc(ENCODE(Csum % 85), outfile); /* Checksum for every line. */
  1156.       fputc('\n', outfile);
  1157.     }
  1158.   }
  1159.   else
  1160.   {
  1161.     fputc(ch, outfile);
  1162.     linepos ++;
  1163.  
  1164.     if (new_version)
  1165.     {
  1166.       calcchecksum(ch);
  1167.       if (linepos >= (MAXPERLINE-1))
  1168.       {
  1169.         fputc(ENCODE(Csum % 85), outfile); /* Checksum for every line. */
  1170.         fputc('\n', outfile);
  1171.         linepos = 0;
  1172.       }
  1173.     }
  1174.     else  /* Old version */
  1175.       if (linepos >= MAXPERLINE)
  1176.       {
  1177.         fputc('\n', outfile);
  1178.         linepos = 0;
  1179.       }
  1180.  
  1181.   }
  1182. }
  1183.  
  1184.  
  1185. /* Remove paths from a file name. */
  1186. BYTE *truncname(name)
  1187. register BYTE *name;
  1188. {
  1189.   register BYTE ch, *newname;
  1190.  
  1191.   newname = name;
  1192.   while ((ch = *name++) != 0)
  1193.     if (ch == '/' || ch == ':')
  1194.       newname = name;
  1195.  
  1196.   return(newname);
  1197. }
  1198. SHAR_EOF
  1199. cat << \SHAR_EOF > btoa.h
  1200. /* btoa.h */
  1201.  
  1202. #define MAXPERLINE      78
  1203. #define BUFSIZE         100
  1204. #define TRUE            1
  1205. #define FALSE           0
  1206. #define USE_MACROS      TRUE
  1207.  
  1208. #define BYTE            char
  1209. #define WORD            short
  1210. #define LONG            long
  1211.  
  1212. #define ENCODE(ch)      ( (int) ((ch) + '!') )
  1213. #define DECODE(ch)      ( (int) ((ch) - '!') )
  1214.  
  1215. struct Diagnosis
  1216. {
  1217.   LONG startpos, endpos;  /* Line before and after erroneous area */
  1218.   struct Diagnosis *next, *last;
  1219. };
  1220.  
  1221.  
  1222. /*
  1223. Following functions have been converted to macros:
  1224.   calcchecksum()
  1225. */
  1226.  
  1227.  
  1228. #if LATTICE  /* Prototypes for Lattice C */
  1229.  
  1230. void asciiout(int), exit(int),
  1231.      intodiagnosislist(struct Diagnosis *, LONG, LONG),
  1232.      outdiagnosislist(struct Diagnosis *, LONG *, LONG *), printhelp(void),
  1233.      producediagnosis(struct Diagnosis *, FILE *), wordout(LONG);
  1234.  
  1235. BYTE atob(FILE *), btoa(FILE *, BYTE *), copyfile(FILE *, FILE *, BYTE *),
  1236.      decode_line(BYTE *, int), new_decodefile(FILE *, LONG *, LONG, int),
  1237.      old_decodefile(FILE *, LONG *), performrepair(FILE *),
  1238.      producerepair(FILE *), readbuffer(BYTE *, BYTE *, FILE *),
  1239.      *truncname(BYTE *);
  1240.  
  1241. int  nextbyte(FILE *);
  1242.  
  1243. FILE *fopen_read(BYTE *), *fopen_write(BYTE *);
  1244.  
  1245. #if USE_MACROS
  1246. void calcchecksum(int);
  1247. #else
  1248. #include "chksum.h"
  1249. #endif USE_MACROS
  1250.  
  1251. #else !LATTICE  /* For compilers which don't know about prototypes. */
  1252.  
  1253. void asciiout(), exit(), intodiagnosislist(), outdiagnosislist(),
  1254.      printhelp(), producediagnosis(), wordout();
  1255.  
  1256. BYTE atob(), btoa(), copyfile(), decode_line(), new_decodefile(),
  1257.      old_decodefile(), performrepair(), producerepair(), readbuffer(),
  1258.      *truncname();
  1259.  
  1260. int  nextbyte();
  1261.  
  1262. FILE *fopen_read(), *fopen_write();
  1263.  
  1264. #if USE_MACROS
  1265. void calcchecksum();
  1266. #else
  1267. #include "chksum.h"
  1268. #endif USE_MACROS
  1269.  
  1270. #endif LATTICE
  1271. SHAR_EOF
  1272. cat << \SHAR_EOF > chksum.h
  1273. /* chksum.h */
  1274. /* calcchecksum() was converted to a macro for effectivity reasons. */
  1275. /* Don't (!!) give it an argument that has to be evaluated. This    */
  1276. /* is guaranteed to slow it down.                                   */
  1277.  
  1278. /* Update file checksums. */
  1279.  
  1280. #define calcchecksum(ch)        \
  1281. {                               \
  1282.   extern LONG Ceor, Csum, Crot; \
  1283.                                 \
  1284.   Ceor ^= ch;                   \
  1285.   Csum += ch + 1;               \
  1286.                                 \
  1287.   if (Crot & 0x80000000L)       \
  1288.   {                             \
  1289.     Crot <<= 1;                 \
  1290.     Crot ++;                    \
  1291.   }                             \
  1292.   else                          \
  1293.     Crot <<= 1;                 \
  1294.                                 \
  1295.   Crot += ch;                   \
  1296. }
  1297. SHAR_EOF
  1298. cat << \SHAR_EOF > repair.c
  1299. /* repair.c */
  1300.  
  1301. /* Written by Stefan Parmark. */
  1302.  
  1303. #include <stdio.h>
  1304. #ifdef AMIGA
  1305. #include <stdlib.h>
  1306. #include <string.h>
  1307. #endif AMIGA
  1308.  
  1309. #include "btoa.h"
  1310.  
  1311. /* File names. */
  1312. BYTE *diagnosisname   = "btoa.dia";
  1313. BYTE *repairname      = "btoa.rep";
  1314. BYTE *repairedname    = "btoa.rdy";
  1315.  
  1316. /* File headers. */
  1317. BYTE *diagnosisheader = "xdiagnosis\n";
  1318. BYTE *repairheader    = "xrepair\n";
  1319.  
  1320.  
  1321. /* Produce diagnosis file from diagnoses records created by atob(). */
  1322. /* It contains the lines immediately before and after the error     */
  1323. /* sequence.                                                        */
  1324. void producediagnosis(diagnosislist, infile)
  1325. register struct Diagnosis *diagnosislist;
  1326. register FILE *infile;
  1327. {
  1328.   register FILE *diagnosisfile;
  1329.   LONG startpos, endpos;
  1330.   register LONG currentpos;
  1331.   extern BYTE *diagnosisname, *diagnosisheader, buffer[BUFSIZE];
  1332.  
  1333.   currentpos = ftell(infile);
  1334.  
  1335.   if ((diagnosisfile = fopen_write(diagnosisname)) != NULL)
  1336.   {
  1337.     fprintf(stderr, "btoa: Diagnosis output to '%s'.\n", diagnosisname);
  1338.  
  1339.     fputs(diagnosisheader, diagnosisfile);
  1340.     do
  1341.     {
  1342.       /* Extract startpos & endpos from diagnosislist. */
  1343.       outdiagnosislist(diagnosislist, &startpos, &endpos);
  1344.  
  1345.       if (startpos != -1)
  1346.       {
  1347.         /* Print line before error. */
  1348.         fseek(infile, startpos, 0);
  1349.         fgets(buffer, BUFSIZE, infile);
  1350.         fputs(buffer, diagnosisfile);
  1351.  
  1352.         /* Print line after error. */
  1353.         fseek(infile, endpos, 0);
  1354.         fgets(buffer, BUFSIZE, infile);
  1355.         fputs(buffer, diagnosisfile);
  1356.       }
  1357.     }
  1358.     while (startpos != -1);
  1359.     fputs(diagnosisheader, diagnosisfile);
  1360.  
  1361.     fclose(diagnosisfile);
  1362.   }
  1363.  
  1364.   /* Move file pointer to where it was when we entered. */
  1365.   fseek(infile, currentpos, 0);
  1366. }
  1367.  
  1368.  
  1369. /* Insert two file positions into diagnosislist. */
  1370. void intodiagnosislist(diagnosislist, startpos, endpos)
  1371. register struct Diagnosis *diagnosislist;
  1372. register LONG startpos, endpos;
  1373. {
  1374.   register struct Diagnosis *diagnosisitem, *lastitem;
  1375.  
  1376.   diagnosisitem = (struct Diagnosis *)malloc(sizeof(struct Diagnosis));
  1377.   diagnosisitem->startpos = startpos;
  1378.   diagnosisitem->endpos = endpos;
  1379.   diagnosisitem->next = NULL;
  1380.  
  1381.   if ((lastitem = diagnosislist->last) == NULL)  /* List is empty */
  1382.     diagnosislist->next = diagnosislist->last = diagnosisitem;
  1383.   else
  1384.   {
  1385.     if (lastitem->endpos >= startpos)
  1386.     {
  1387.       lastitem->endpos = endpos;
  1388.       free((BYTE *) diagnosisitem);
  1389.     }
  1390.     else
  1391.     {
  1392.       lastitem->next = diagnosisitem;
  1393.       diagnosislist->last = diagnosisitem;
  1394.     }
  1395.   }
  1396. }
  1397.  
  1398.  
  1399. /* Extract two file positions from diagnosislist. */
  1400. void outdiagnosislist(diagnosislist, startpos, endpos)
  1401. register struct Diagnosis *diagnosislist;
  1402. LONG *startpos, *endpos;
  1403. {
  1404.   register struct Diagnosis *diagnosisitem;
  1405.  
  1406.   if ((diagnosisitem = diagnosislist->next) == NULL)  /* List is empty */
  1407.     *startpos = *endpos = -1;
  1408.   else
  1409.   {
  1410.     *startpos = diagnosisitem->startpos;
  1411.     *endpos = diagnosisitem->endpos;
  1412.  
  1413.     diagnosislist->next = diagnosisitem->next;
  1414.     free((BYTE *)diagnosisitem);
  1415.     if (diagnosislist->next == NULL)
  1416.       diagnosislist->last = NULL;
  1417.   }
  1418. }
  1419.  
  1420.  
  1421. /* Copy infile to outfile until searchstring is found. If outfile */
  1422. /* is NULL nothing will be written.                               */
  1423. BYTE copyfile(infile, outfile, searchstring)
  1424. register FILE *infile, *outfile;
  1425. register BYTE *searchstring;
  1426. {
  1427.   register BYTE stop, error;
  1428.   static BYTE copybuffer[BUFSIZE];
  1429.  
  1430.   stop = error = FALSE;
  1431.   while (!(stop || error))
  1432.     if (readbuffer(copybuffer, "archive", infile))
  1433.       error = TRUE;
  1434.     else
  1435.     {
  1436.       if (outfile != NULL)
  1437.         fputs(copybuffer, outfile);
  1438.       if (strcmp(copybuffer, searchstring) == 0)
  1439.         stop = TRUE;
  1440.     }
  1441.  
  1442.   return(error);
  1443. }
  1444.  
  1445.  
  1446. /* Read a line from infile into buffer. Returns TRUE if */
  1447. /* end-of-file has been reached.                        */
  1448. BYTE readbuffer(buffer, errormsg, infile)
  1449. register BYTE *buffer, *errormsg;
  1450. register FILE *infile;
  1451. {
  1452.   register BYTE error;
  1453.  
  1454.   error = FALSE;
  1455.   if (fgets(buffer, BUFSIZE, infile) == NULL)
  1456.   {
  1457.     fprintf(stderr, "btoa: Unexpected end of %s file.\n", errormsg);
  1458.     error = TRUE;
  1459.   }
  1460.  
  1461.   return(error);
  1462. }
  1463.  
  1464.  
  1465. FILE *fopen_read(filename)
  1466. register BYTE *filename;
  1467. {
  1468.   register FILE *infile;
  1469.  
  1470.   if ((infile = fopen(filename, "r")) == NULL)
  1471.     fprintf(stderr, "btoa: Can't open '%s' for input.\n", filename);
  1472.  
  1473.   return(infile);
  1474. }
  1475.  
  1476.  
  1477. FILE *fopen_write(filename)
  1478. register BYTE *filename;
  1479. {
  1480.   register FILE *outfile;
  1481.  
  1482.   if ((outfile = fopen(filename, "w")) == NULL)
  1483.     fprintf(stderr, "btoa: Can't open '%s' for output.\n", filename);
  1484.  
  1485.   return(outfile);
  1486. }
  1487.  
  1488.  
  1489. /* Extract lines from original archive to fix the damaged one. */
  1490. BYTE producerepair(infile)
  1491. register FILE *infile;
  1492. {
  1493.   register FILE *repairfile, *diagnosisfile;
  1494.   register BYTE error, stop;
  1495.   static BYTE *errormsg = "diagnosis";
  1496.   extern BYTE *diagnosisname, *diagnosisheader, *repairname, *repairheader,
  1497.               buffer[BUFSIZE];
  1498.  
  1499.   error = FALSE;
  1500.   diagnosisfile = repairfile = NULL;
  1501.  
  1502.   fprintf(stderr, "btoa: Repair output to '%s'.\n", repairname);
  1503.   if ((diagnosisfile = fopen_read(diagnosisname)) == NULL)
  1504.     error = TRUE;
  1505.   else if ((repairfile = fopen_write(repairname)) == NULL)
  1506.   {
  1507.     fclose(diagnosisfile);
  1508.     diagnosisfile = NULL;
  1509.     error = TRUE;
  1510.   }
  1511.   else
  1512.   {
  1513.     /* Read until header is found. This makes it possible to   */
  1514.     /* have junk before the header, such as an article header. */
  1515.     do
  1516.     {
  1517.       if (readbuffer(buffer, errormsg, diagnosisfile))
  1518.         error = TRUE;
  1519.     }
  1520.     while (!error && strcmp(buffer, diagnosisheader) != 0);
  1521.     fputs(repairheader, repairfile);
  1522.   }
  1523.  
  1524.   stop = FALSE;
  1525.   while (!(error || stop))
  1526.   {
  1527.     /* Loop until header is found again. */
  1528.  
  1529.     if (readbuffer(buffer, errormsg, diagnosisfile))
  1530.       error = TRUE;
  1531.     else if (strcmp(buffer, diagnosisheader) == 0)
  1532.       stop = TRUE;
  1533.     else
  1534.     {
  1535.       /* Read until line before error is found. */
  1536.       error = copyfile(infile, NULL, buffer);
  1537.       if (!error)
  1538.       {
  1539.         /* Print line before error. */
  1540.         fputs(buffer, repairfile);
  1541.  
  1542.         if (readbuffer(buffer, errormsg, diagnosisfile))
  1543.           error = TRUE;
  1544.         else
  1545.         {
  1546.           /* Print line after error */
  1547.           fputs(buffer, repairfile);
  1548.           /* Copy infile to repairfile until line after error */
  1549.           error = copyfile(infile, repairfile, buffer);
  1550.         }
  1551.       }
  1552.     }
  1553.   }
  1554.  
  1555.   if (!error)
  1556.     fputs(repairheader, repairfile);
  1557.  
  1558.   if (repairfile != NULL)
  1559.     fclose(repairfile);
  1560.   if (diagnosisfile != NULL)
  1561.     fclose(diagnosisfile);
  1562.  
  1563.   return(error);
  1564. }
  1565.  
  1566.  
  1567. /* Repair damaged archive from repair file. */
  1568. BYTE performrepair(infile)
  1569. register FILE *infile;
  1570. {
  1571.   register FILE *repairfile, *outfile;
  1572.   register BYTE error, stop;
  1573.   static BYTE *errormsg = "repair";
  1574.   extern BYTE *repairname, *repairedname, *repairheader, buffer[BUFSIZE];
  1575.  
  1576.   error = FALSE;
  1577.   repairfile = outfile = NULL;
  1578.  
  1579.   if ((repairfile = fopen_read(repairname)) == NULL)
  1580.     error = TRUE;
  1581.   else if ((outfile = fopen_write(repairedname)) == NULL)
  1582.   {
  1583.     fclose(repairfile);
  1584.     repairfile = NULL;
  1585.     error = TRUE;
  1586.   }
  1587.   else
  1588.   {
  1589.     fprintf(stderr, "btoa: Repaired archive written to '%s'.\n", repairedname);
  1590.  
  1591.     /* Read until header is found. */
  1592.     do
  1593.     {
  1594.       if (readbuffer(buffer, errormsg, repairfile))
  1595.         error = TRUE;
  1596.     }
  1597.     while (!error && strcmp(buffer, repairheader) != 0);
  1598.   }
  1599.  
  1600.   stop = FALSE;
  1601.   while (!(error || stop))
  1602.   {
  1603.     /* Loop until header is found. */
  1604.  
  1605.     if (readbuffer(buffer, errormsg, repairfile))
  1606.       error = TRUE;
  1607.     else if (strcmp(buffer, repairheader) == 0)
  1608.       stop = TRUE;
  1609.     else
  1610.     {
  1611.       /* Read and write until line before error. */
  1612.       error = copyfile(infile, outfile, buffer);
  1613.       if (!error)
  1614.         if (readbuffer(buffer, errormsg, repairfile))
  1615.           error = TRUE;
  1616.         else
  1617.         {
  1618.           /* Read and write until line after error. */
  1619.           error = copyfile(repairfile, outfile, buffer);
  1620.           /* Skip until line after error */
  1621.           copyfile(infile, NULL, buffer);
  1622.         }
  1623.     }
  1624.   }
  1625.  
  1626.   if (!error)  /* Write rest of archive. */
  1627.     while (fgets(buffer, BUFSIZE, infile) != NULL)
  1628.       fputs(buffer, outfile);
  1629.  
  1630.   if (outfile != NULL)
  1631.     fclose(outfile);
  1632.   if (repairfile != NULL)
  1633.     fclose(repairfile);
  1634.  
  1635.   return(error);
  1636. }
  1637. SHAR_EOF
  1638. #    End of shell archive
  1639. exit 0
  1640. -- 
  1641. Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
  1642.